package com.oro.backingbeans;

import java.io.IOException;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.faces.application.FacesMessage;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import com.oro.util.FacesUtils;

public class LoginBean {

	private static final Logger logger = Logger.getLogger(LoginBean.class);
	private AuthenticationManager authenticationManager;
	private String password;

	private String username;

	public LoginBean() {

		// This snippet of code from our LoginBean will catch exceptions thrown
		// by Spring Security so that we can display them in our JSF page
		// {
		// Exception ex = (Exception) FacesContext
		// .getCurrentInstance()
		// .getExternalContext()
		// .getSessionMap()
		// .get(AbstractProcessingFilter.SPRING_SECURITY_LAST_EXCEPTION_KEY);
		//
		// if (ex != null)
		// FacesContext.getCurrentInstance().addMessage(
		// null,
		// new FacesMessage(FacesMessage.SEVERITY_ERROR, ex
		// .getMessage(), ex.getMessage()));
		// }

	}

	// managed properties for the login page, username/password/etc...

	// This works
	// This is the action method called when the user clicks the "login" button
	public String doLogin() throws IOException, ServletException {
		ExternalContext context = FacesContext.getCurrentInstance()
				.getExternalContext();

		RequestDispatcher dispatcher = ((ServletRequest) context.getRequest())
				.getRequestDispatcher("/j_spring_security_check?j_username="
						+ username + "&j_password=" + password);

		dispatcher.forward((ServletRequest) context.getRequest(),
				(ServletResponse) context.getResponse());

		FacesContext.getCurrentInstance().responseComplete();
		// It's OK to return null here because Faces is just going to exit.
		return null;
	}

	public AuthenticationManager getAuthenticationManager() {
		return authenticationManager;
	}

	private Logger getLogger() {
		return logger;
	}

	public String getPassword() {
		return password;
	}

	public String getUsername() {
		return username;
	}

	// This works, but follows the navigation-rule instead of taking you to the
	// secured page
	public void login() throws java.io.IOException {
		HttpServletRequest req = (HttpServletRequest) FacesContext
				.getCurrentInstance().getExternalContext().getRequest();
		System.out.println("The method is: " + req.getMethod());
		FacesContext
				.getCurrentInstance()
				.getExternalContext()
				.redirect(
						"j_spring_security_check?j_username=" + username
								+ "&j_password=" + password);
	}

	public void loginIce() throws java.io.IOException {
		FacesContext
				.getCurrentInstance()
				.getExternalContext()
				.redirect(
						"/oro/j_spring_security_check?j_username=" + username
								+ "&j_password=" + password);
	}

	public void loginJavaRanch() throws java.io.IOException {
		FacesContext
				.getCurrentInstance()
				.getExternalContext()
				.dispatch(
						"/j_spring_security_check?j_username=" + username
								+ "&j_password=" + password);
		FacesContext.getCurrentInstance().responseComplete();
	}

	public String loginMaven() {
		try {
			Authentication request = new UsernamePasswordAuthenticationToken(
					this.getUsername(), getPassword());
			Authentication result = authenticationManager.authenticate(request);
			SecurityContextHolder.getContext().setAuthentication(result);

		} catch (AuthenticationException e) {
			String loginFailedMessage = FacesUtils.getBundleKey("msg",
					"login.failed");
			FacesUtils.addErrorMessage(loginFailedMessage);
			return null;
		}
		return "loginSuccess";
	}

	public void loginWeird() throws IOException {
		try {
			Authentication authentication = SecurityContextHolder.getContext()
					.getAuthentication();
			UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(
					username, password);
			authToken.setDetails(authentication.getDetails());

			FacesContext context = FacesContext.getCurrentInstance();
			ExternalContext ec = context.getExternalContext();
			((HttpServletRequest) ec.getRequest())
					.getSession()
					.setAttribute(
							UsernamePasswordAuthenticationFilter.SPRING_SECURITY_LAST_USERNAME_KEY,
							authToken.getName());

			Authentication newAuth = authenticationManager
					.authenticate(authToken);
			SecurityContextHolder.getContext().setAuthentication(newAuth);
		} catch (UsernameNotFoundException unfe) {
			FacesContext.getCurrentInstance().addMessage(
					null,
					new FacesMessage(FacesMessage.SEVERITY_ERROR, unfe
							.getMessage(), unfe.getMessage()));
		}

		ExternalContext ec = FacesContext.getCurrentInstance()
				.getExternalContext();
		String encodedURL = ec.encodeResourceURL(ec.getRequestContextPath()
				+ "/test.xhtml");

		((HttpServletResponse) ec.getResponse()).sendRedirect(encodedURL);
	}

	@PostConstruct
	public void postConstruct() {
		getLogger().info("LoginBean has been constructed.");
	}

	@PreDestroy
	public void preDestroy() {
		getLogger().info("LoginBean is being destroyed.");
	}

	public void setAuthenticationManager(
			AuthenticationManager authenticationManager) {
		this.authenticationManager = authenticationManager;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public void setUsername(String username) {
		this.username = username;
	}

}